home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TPUG - Toronto PET Users Group
/
TPUG Users Group CD
/
TPUG Users Group CD.iso
/
AMIGA
/
AMICUS
/
AMICUS14.ADF
/
Clocks
/
wClock
/
wClock.s
< prev
Wrap
Text File
|
1989-01-28
|
10KB
|
311 lines
* windowClock
*
* This is a simple clock that displays the time in 24-hr mode to the nearest
* minute. It will bring itself to the front anytime a new minute occurs.
* It will not be overwritten when it becomes active or inactive as was true
* for some of it's ancestors.
* Code size : 676 bytes
* Minimum stack size : 1600 bytes
* Memory used when running : 6968 bytes
* I kept all code in this section so that it would all be loaded in the
* same hunk and thus allow it to be refered to using x(PC) addressing.
* Some rather inventive subroutine calling is used in the main loop to
* save a little time. The return address is kept in A4 and since it is
* almost always the same this speeds up the process compared to BSR..RTS
* The majority of this code consists of initialization and termination code.
* I do not think it will work from the workbench as it is right now.
* This file will assemble rather quickly since it does not use any include
* files. It did at one time but that file was lost so I disassembled this
* file and then went through it and put in comments.
* I hope it is not hard to understand and that it will prove educational to
* someone.
* Darrel Schneider
***** open intuition library and store its pointer into D2 *****
LEA IntuitionName(PC),A1
MOVEQ #0,D0 ; load version number
MOVEA.L 4,A6 ; load exec library address
JSR -$228(A6) ; call OpenLibrary
TST.L D0
BNE.S *+4
RTS ; FAIL: couldn't open intuition library
MOVE.L D0,D2 ; store intuition library pointer
***** open clock window *****
; I tried allocating and initializing the NewWindow structure
; on the stack in order to save a few bytes and it did BUT just a few.
; If it hadn't been for all the NULL fields it would have been larger.
; use stack for the NewWindow structure
LINK A2,#-$30
MOVEA.L A7,A1 ; load NewWindow pointer
MOVEQ #$B,D0 ; loop count
; this loop clears the NewWindow structure
CLR.L (A1)+
DBF D0,*-2
ADDQ.B #1,-(A1) ; make it a WBENCHSCREEN
MOVEA.L A7,A1 ; load NewWindow pointer
MOVE.L #$1F20000,(A1)+ ; left edge = $1f2, top edge = 0
MOVE.L #$56000A,(A1)+ ; Width = $56, Height = $A
NOT.W (A1)+ ; default pens (-1)
MOVE.L #$C0200,(A1)+ ; IDCMPflags = CLOSEWINDOW!ACTIVEWINDOW!INACTIVEWINDOW
MOVE.L #$3000A,(A1)+ ; flags = WINDOWCLOSE!SMART_REFRESH!WINDOWDRAG!NOCAREREFRESH!RMBTRAP
MOVEA.L A7,A0 ; load NewWindow pointer
EXG D2,A6
JSR -$CC(A6) ; call OpenWindow
EXG D2,A6
UNLK A2 ; discard the NewWindow structure
TST.L D0
BEQ.L FailOpenWindow
WindowOpened:
MOVE.L D0,A3 ; store window pointer
; get ClockWindow->UserPort->mp_SigBit into D0
MOVEA.L $56(A3),A0 ; A0 = ClockWindow->UserPort
MOVEQ #0,D0
MOVE.B $F(A0),D0 ; D0 = the ClockWindow's mp_SigBit
MOVEQ #1,D4
LSL.L D0,D4 ; D4 = windowSigs
MOVE.L D4,D7 ; D7 = waitFlags
***** create timer port *****
; get a signal bit
MOVEQ #-1,D0
JSR -$14A(A6) ; call AllocSignal
MOVE.L D0,D3 ; D3 = sigBit
BMI.S FailCreateTimer1
; alloc port structure
MOVEQ #$22,D0 ; size of structure
MOVE.L #$10001,D1 ; memory type = CLEAR and PUBLIC
JSR -$C6(A6) ; call AllocMem
MOVE.L D0,D5 ; D5 = timer Port
BNE.S SkipFailCode
; AllocMem failed
MOVE.L D3,D0
JSR -$150(A6) ; call FreeSignal
BRA.S FailCreateTimer2
SkipFailCode:
; fill port fields
MOVEA.L D5,A2
ADDQ.L #8,A2 ; A2 now points to the LN_TYPE field
MOVE.W #$400,(A2)+ ; LN_TYPE = NT_MSGPORT, LN_PRI = 0
LEA TimerPortName(PC),A0
MOVE.L A0,(A2)+ ; LN_NAME = address of timer port name
MOVE.W D3,(A2)+ ; MP_FLAGS = (#PA_SIGNAL=0), MP_SIGBIT = sigBit
MOVEQ #0,D0
MOVEA.L D0,A1
JSR -$126(A6) ; call FindTask ( 0 arg means this task)
MOVE.L D0,(A2) ; MP_SIGTASK = pointer to found task
BRA.S SkipFailSection
********** FAILURE SECTION ************
ClosedWindow:
; abort any standing timer request
MOVEA.L A5,A1
; ABORTIO System Macro
MOVE.L A6,-(A7)
MOVEA.L $14(A1),A6
JSR -$24(A6)
MOVEA.L (A7)+,A6
; close timer device
MOVEA.L A5,A1
JSR -$1C2(A6) ; call CloseDevice
; deallocate timeRequest structure
MOVEQ #-1,D6
MOVE.B D6,8(A5)
MOVE.L D6,$14(A5)
MOVE.L D6,$18(A5)
MOVEA.L A5,A1
MOVEQ #$28,D0
JSR -$D2(A6) ; call FreeMem
FailOpenDevice:
FailTimeRequestAlloc:
; close timer port
MOVEA.L D5,A1
JSR -$168(A6) ; call RemPort
MOVEA.L D5,A2
; D6 = -1
MOVE.B D6,$A(A2)
MOVE.L D6,(A2)
MOVE.L (SP)+,D0 ; get the sigBit
JSR -$150(A6) ; call FreeSignal
MOVEA.L D5,A1
MOVEQ #$22,D0
JSR -$D2(A6) ; call FreeMem
FailCreateTimer2:
FailCreateTimer1:
MOVEA.L A3,A0
EXG D2,A6
JSR -$48(A6) ; call CloseWindow
EXG D2,A6
FailOpenWindow:
MOVEA.L D2,A1 ; Intuition Library
JSR -$19E(A6) ; call CloseLibrary
MOVEQ #0,D0 ; this is the return value
RTS
********* FAILURE END **********
SkipFailSection:
; add the port
MOVEA.L D5,A1
JSR -$162(A6) ; call AddPort
***** use the timer port sigBit(D3) to set the timeOutSig(D6) *****
MOVE.L D3,D0
MOVE.L D3,-(SP) ; save the sigBit
MOVEQ #1,D6
LSL.L D0,D6
OR.L D6,D7 ; update the waitFlags
***** initialize timeRequest structure *****
MOVEQ #$28,D0 ; D0 = IOTV_SIZE
MOVE.L #$10001,D1 ; memory type = clear it, and public
JSR -$C6(A6) ; call AllocMem
TST.L D0
BEQ.S FailTimeRequestAlloc
MOVEA.L D0,A5 ; A5 = timeRequest
MOVE.W #$500,8(A5) ; LN_TYPE = NT_MESSAGE(5), LN_PRI = 0
MOVE.L D5,$E(A5) ; MN_REPLYPORT = timerPort
; AllocMem set to zero the IO_FLAGS, IO_ERROR fields
***** open vblank timer device *****
LEA TimerName(PC),A0 ; A0 = timer name
MOVEA.L A5,A1 ; A1 = timeRequest
MOVEQ #1,D0 ; D0 = UNIT_VBLANK(1)
MOVEQ #0,D1
JSR -$1BC(A6) ; call OpenDevice
TST.L D0
BNE.S FailOpenDevice
MOVE.W #9,$1C(A5) ; IO_COMMAND = TR_ADDREQUEST(9)
***** initialize main loop *****
LEA buffer(PC),A2 ; A2 = bufferPTR
LEA InitMainLoop(PC),A4
BRA.S InitializeTime
InitMainLoop:
LEA WhileMoreMessages(PC),A4
MainLoop:
MOVE.L D7,D0 ; D0 = waitFlags
JSR -$13E(A6) ; call Wait
MOVE.L D0,D3 ; save what woke the Wait up into D3
AND.L D6,D0 ; was it the timeoutSig(D6)?
BEQ.S isItAWindowSig ; if it wasn't branch
BRA.S SetAndPrintTime
isItAWindowSig:
AND.L D4,D3 ; was what woke the Wait up a windowSig(D4)?
BEQ.S MainLoop ; if not restart the main loop
; keep doing the loop While there are window messages
WhileMoreMessages:
MOVEA.L $56(A3),A0 ; A0 = window's UserPort
JSR -$174(A6) ; call GetMsg
TST.L D0 ; D0 = message
BEQ.S MainLoop ; no more messages so start Waiting
MOVEA.L D0,A1
MOVE.W $16(A1),-(A7) ; save the messages im_Class
JSR -$17A(A6) ; call ReplyMessage
CMPI.W #$200,(A7)+ ; was the message type CLOSEWINDOW?
BEQ.L ClosedWindow ; Yes so branch to termination code.
; No so refresh the window by printing the time.
; falls through to PrintTime
************************************
PrintTime:
MOVEA.L $32(A3),A0 ; window's RPort
LEA Date_Text(PC),A1 ; Date_Text structure
MOVEQ #0,D0
MOVEQ #0,D1
EXG D2,A6
JSR -$D8(A6) ; call PrintIText
MOVEA.L A3,A0
JSR -$138(A6) ; call WindowToFront
EXG D2,A6
JMP (A4) ; normally jumps to WhileMoreMessages
*****************************
SetAndPrintTime:
MOVEA.L D5,A0 ; get message form timer port
JSR -$174(A6) ; call GetMsg
InitializeTime:
; initialize the buffer
MOVE.L #$2030303A,(A2)+ ; buffer[0-3] = " 00:"
MOVE.L #$30302000,(A2) ; buffer[4-7] = "00 "0
; set the timeRequest to wait for a minute
MOVE.W #$3B,$22(A5) ; TV_SECS = $3B(59 seconds)
MOVE.L #$F423F,$24(A5) ; TV_MICRO= MICRO_PER_SEC-1
; get the current time. It will be on the stack
SUBQ.L #4,A7
LEA (A7),A1 ; address of micros
SUBQ.L #4,A7
LEA (A7),A0 ; address of seconds
EXG D2,A6
JSR -$54(A6) ; call CurrentTime
EXG D2,A6
MOVE.L (A7)+,D0 ; secs
MOVE.L (A7)+,D1 ; micros
SUB.L D1,$24(A5) ; subtract micros from TV_MICRO
CLR.W -(A7) ; push a zero word onto the stack => AM
DIVU #-$5740,D0 ; secs/#secs_in_12hrs
LSR.B #1,D0 ; test least sig. bit by shifting into C bit
BCC.S AM
; it is PM
MOVE.W #$C,(A7) ; top of stack now 12 => PM
AM:
SWAP D0 ; lower half of D0 = #of secs in the half day
MOVE.L D0,D1 ; save D0 into D1
MOVEQ #0,D0
MOVE.W D1,D0 ;
DIVU #$3C,D0 ; #of_secs_in_half_day/60
MOVE.W D0,-(A7) ; save the #of minutes*hrs in the half day
SWAP D0 ; D0.W = # of secs in the minute
SUB.W D0,$22(A5) ; subtract this from the TV_SECS
; start the timer running
MOVEA.L A5,A1
JSR -$1CE(A6) ; call SendIO
; figure out what time it is and load it in the buffer
MOVEQ #0,D0
MOVE.W (A7)+,D0 ; D0 has # of minutes*hrs in half day
DIVU #$3C,D0 ; divide it by 60; rem = minutes, quot = hrs
MOVEQ #0,D1
MOVE.W (A7)+,D1 ; D1 = (0=AM), (12=PM)
ADD.W D0,D1 ; add quot to D1 giving # of hrs in the day
SWAP D0 ; get the rem = minutes
EXT.L D0
DIVU #$A,D0 ; divide by 10; rem = ones digit, quot = tens digit
ADD.B D0,(A2)+ ; add tens digit to buffer[4]
SWAP D0
ADD.B D0,(A2) ; add ones digit to buffer[5]
DIVU #$A,D1 ; divide hours by 10; rem = ones digit, quot = tens digit
SUBQ.L #4,A2 ; set bufferPTR to buffer[1]
ADD.B D1,(A2)+ ; add tens digit to buffer[1]
SWAP D1
ADD.B D1,(A2) ; add ones digit to buffer[2]
SUBQ.L #2,A2 ; set bufferPTR to buffer[0]
BRA.L PrintTime ; PrintTime will return
**********************************************************
TimerPortName:
DC.B 'timer',0
TimerName:
DC.B 'timer.device',0,0
IntuitionName:
DC.B 'intuition.library',0
Date_Text:
DC.B 1,0,1,0
DC.W 29,1
DC.L 0,buffer,0
buffer:
DS.B 8